<template>
  <div class="validate-input-container pb-3">
    <!--
      @blur:input框失去焦点
      @input:input框值改变时触发
      v-bind:动态地绑定一个或多个attribute(v-bind:src简写:src)
      $attrs:接收父组件传递给的 attribute，包括class和style，配合inheritAttrs: false
    -->
    <input
      v-if="tag !== 'textarea'"
      class="form-control"
      :class="{'is-invalid': inputRef.error}"
      @blur="validateInput"
      v-model="inputRef.val"
      v-bind="$attrs"
    >
    <textarea
      v-else
      class="form-control"
      :class="{'is-invalid': inputRef.error}"
      @blur="validateInput"
      v-model="inputRef.val"
      v-bind="$attrs"
    >
    </textarea>
    <span v-if="inputRef.error" class="invalid-feedback">{{inputRef.message}}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, reactive, onMounted, computed } from 'vue'
import { emitter } from './ValidateForm.vue'
// 邮件正则
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
const passwordReg = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,12}$/
interface RuleProp {
  type: 'required' | 'email' | 'password' | 'custom';
  message: string;
  validator?: () => boolean; // 自定义规则
}
// type 类型别名
export type RulesProp = RuleProp[]
export type TagType = 'input' | 'textarea'

export default defineComponent({
  props: {
    rules: Array as PropType<RulesProp>, // type,required 属于props验证  as 类型断言
    modelValue: String, // 接受父组件v-model传递过来的的值
    tag: { // 是input框还是textarea框
      type: String as PropType<TagType>,
      default: 'input'
    }
  },
  // 不希望组件中的根元素继承父组件传递的attribute 只希望用在有v-bind="$attrs" 的属性上
  inheritAttrs: false,
  setup (props, context) {
    const inputRef = reactive({
      val: computed({ // get set :computed的另一种写法默认使用get
        get: () => props.modelValue || '', // 默认的
        set: val => { // 更新时 向外触发事件 更新v-model上的值
          context.emit('update:modelValue', val)
        }
      }),
      error: false,
      message: ''
    })
    // 鼠标失去焦点表单验证
    const validateInput = () => {
      if (props.rules) {
        // every方法用于检测数组所有元素是否都符合指定条件,如果数组中检测到有一个元素不满足，则整个表达式返回 false
        const allPassed = props.rules.every(rule => {
          let passed = true
          inputRef.message = rule.message
          switch (rule.type) {
            case 'required':
              passed = (inputRef.val.trim() !== '')
              break
            case 'email':
              passed = emailReg.test(inputRef.val)
              break
            case 'custom': // 自定义规则
              passed = rule.validator ? rule.validator() : true
              break
            case 'password':
              passed = passwordReg.test(inputRef.val)
              break
            default:
              break
          }
          return passed
        })
        inputRef.error = !allPassed
        return allPassed
      }
      return true
    }
    onMounted(() => {
      // 向父组件发送事件 emitter.on接收(父子组件信息通讯)鉴定表单的验证结果
      emitter.emit('form-item-created', validateInput)
    })
    return {
      inputRef,
      validateInput
    }
  }
})
</script>

<style>

</style>
